#if !defined(D3D10_1_DESCRIPTIONS_H)
#define D3D10_1_DESCRIPTIONS_H

#include <cassert>
#include <d3d10_1.h>
#include <rt/Exceptions/COMException.h>

namespace rt { namespace D3D10_1
{
#define D3D10_1_HELPER_STRUCT_SETTER(structType_, methodName_, valueType_, structMember_)	\
	structType_ &methodName_(valueType_ value)												\
	{																						\
		this->structMember_ = value;														\
		return *this;																		\
	}
#define D3D10_1_HELPER_SETTER_DESC(structType_, methodName_, structMember_, interfaceType_, descType_, descMember_) \
	structType_ &methodName_(interfaceType_ *texture)	\
	{													\
		descType_ desc;									\
		texture->GetDesc(&desc);						\
		structMember_ = desc.descMember_;				\
		return *this;									\
	}

	struct RenderTargetBlendDescription1 : public D3D10_RENDER_TARGET_BLEND_DESC1
	{
#define RENDER_TARGET_BLEND_DESCRIPTION_SETTER(valueType_, structMember_)	\
	D3D10_1_HELPER_STRUCT_SETTER(RenderTargetBlendDescription1, structMember_##_, valueType_, structMember_)

		explicit RenderTargetBlendDescription1() : D3D10_RENDER_TARGET_BLEND_DESC1()
		{
			BlendEnable = FALSE;
			SrcBlend = D3D10_BLEND_ONE;
			DestBlend = D3D10_BLEND_ZERO;
			BlendOp = D3D10_BLEND_OP_ADD;
			SrcBlendAlpha = D3D10_BLEND_ONE;
			DestBlendAlpha = D3D10_BLEND_ZERO;
			BlendOpAlpha = D3D10_BLEND_OP_ADD;
			RenderTargetWriteMask = 0xFF;
		}
		RENDER_TARGET_BLEND_DESCRIPTION_SETTER(BOOL, BlendEnable)
		RENDER_TARGET_BLEND_DESCRIPTION_SETTER(D3D10_BLEND, SrcBlend)
		RENDER_TARGET_BLEND_DESCRIPTION_SETTER(D3D10_BLEND, DestBlend)
		RENDER_TARGET_BLEND_DESCRIPTION_SETTER(D3D10_BLEND_OP, BlendOp)
		RENDER_TARGET_BLEND_DESCRIPTION_SETTER(D3D10_BLEND, SrcBlendAlpha)
		RENDER_TARGET_BLEND_DESCRIPTION_SETTER(D3D10_BLEND, DestBlendAlpha)
		RENDER_TARGET_BLEND_DESCRIPTION_SETTER(D3D10_BLEND_OP, BlendOpAlpha)
		RENDER_TARGET_BLEND_DESCRIPTION_SETTER(UINT8, RenderTargetWriteMask)

#undef RENDER_TARGET_BLEND_DESCRIPTION_SETTER
	};

	struct BlendDescription1 : public D3D10_BLEND_DESC1
	{
#define BLEND_DESCRIPTION_SETTER(valueType_, structMember_)	\
	D3D10_1_HELPER_STRUCT_SETTER(BlendDescription1, structMember_##_, valueType_, structMember_)

		explicit BlendDescription1() : D3D10_BLEND_DESC1()
		{
			AlphaToCoverageEnable = FALSE;
			IndependentBlendEnable = FALSE;
			for (UINT i = 0; i < D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
			{
				RenderTarget[i] = RenderTargetBlendDescription1();
			}
		}
		BLEND_DESCRIPTION_SETTER(BOOL, AlphaToCoverageEnable)
		BLEND_DESCRIPTION_SETTER(BOOL, IndependentBlendEnable)

		ID3D10BlendState1 *Create(ID3D10Device1 *device)
		{
			ID3D10BlendState1 *result = 0;
			THR(device->CreateBlendState1(this, &result));
			return result;
		}

#undef BLEND_DESCRIPTION_SETTER
	};

	struct ShaderResourceViewDescription1 : public D3D10_SHADER_RESOURCE_VIEW_DESC1
	{
#define SHADER_RESOURCE_VIEW_DESCRIPTION_SETTER(valueType_, structMember_)	\
	D3D10_1_HELPER_STRUCT_SETTER(ShaderResourceViewDescription1, structMember_##_, valueType_, structMember_)

		explicit ShaderResourceViewDescription1(D3D10_SRV_DIMENSION1 viewDimension)
			: D3D10_SHADER_RESOURCE_VIEW_DESC1()
		{
			ViewDimension = viewDimension;
			Format = DXGI_FORMAT_UNKNOWN;
		}
		SHADER_RESOURCE_VIEW_DESCRIPTION_SETTER(DXGI_FORMAT, Format)

		ID3D10ShaderResourceView1 *Create(ID3D10Device1 *device, ID3D10Resource *resource)
		{
			ID3D10ShaderResourceView1 *result = 0;
			THR(device->CreateShaderResourceView1(resource, this, &result));
			return result;
		}

#undef SHADER_RESOURCE_VIEW_DESCRIPTION_SETTER
	};

	struct ShaderTextureCubeArrayViewDescription1 : public ShaderResourceViewDescription1
	{
#define SHADER_TEXTURE_CUBE_ARRAY_VIEW_DESCRIPTION_SETTER(valueType_, structMember_)	\
	D3D10_1_HELPER_STRUCT_SETTER(ShaderTextureCubeArrayViewDescription1, \
		structMember_##_, valueType_, TextureCubeArray.structMember_)
#define SHADER_TEXTURE_CUBE_ARRAY_VIEW_DESCRIPTION_SETTER_DESC(structMember_, interfaceType_, descType_, descMember_) \
	D3D10_1_HELPER_SETTER_DESC(ShaderTextureCubeArrayViewDescription1, \
		structMember_##_, TextureCubeArray.structMember_, interfaceType_, descType_, descMember_)

		explicit ShaderTextureCubeArrayViewDescription1()
			: ShaderResourceViewDescription1(D3D10_1_SRV_DIMENSION_TEXTURECUBEARRAY)
		{
			TextureCubeArray.MostDetailedMip = 0;
			TextureCubeArray.MipLevels = ~0U;
			TextureCubeArray.First2DArrayFace = 0;
			TextureCubeArray.NumCubes = ~0U;
		}
		SHADER_TEXTURE_CUBE_ARRAY_VIEW_DESCRIPTION_SETTER(UINT, MostDetailedMip)
		SHADER_TEXTURE_CUBE_ARRAY_VIEW_DESCRIPTION_SETTER(UINT, MipLevels)
		SHADER_TEXTURE_CUBE_ARRAY_VIEW_DESCRIPTION_SETTER(UINT, First2DArrayFace)
		SHADER_TEXTURE_CUBE_ARRAY_VIEW_DESCRIPTION_SETTER(UINT, NumCubes)
		SHADER_TEXTURE_CUBE_ARRAY_VIEW_DESCRIPTION_SETTER_DESC(MipLevels, ID3D10Texture1D, D3D10_TEXTURE1D_DESC, MipLevels - TextureCubeArray.MostDetailedMip)
		SHADER_TEXTURE_CUBE_ARRAY_VIEW_DESCRIPTION_SETTER_DESC(MipLevels, ID3D10Texture2D, D3D10_TEXTURE2D_DESC, MipLevels - TextureCubeArray.MostDetailedMip)
		SHADER_TEXTURE_CUBE_ARRAY_VIEW_DESCRIPTION_SETTER_DESC(MipLevels, ID3D10Texture3D, D3D10_TEXTURE3D_DESC, MipLevels - TextureCubeArray.MostDetailedMip)

#undef SHADER_TEXTURE_CUBE_ARRAY_VIEW_DESCRIPTION_SETTER
#undef SHADER_TEXTURE_CUBE_ARRAY_VIEW_DESCRIPTION_SETTER_DESC
	};

#undef D3D10_1_HELPER_STRUCT_SETTER
} }

#endif
